package com.iflytek.jcy.supervise.job.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Maps;
import com.iflytek.jcy.supervise.job.component.httpinterface.uap.req.TokenDto;
import com.iflytek.sec.uap.dto.organization.OrgExtendDto;
import com.iflytek.sec.uap.dto.role.BaseRole;
import com.iflytek.sec.uap.dto.role.BindRoleListToUserDto;
import com.iflytek.sec.uap.model.UapOrg;
import com.iflytek.sec.uap.model.UapTokenModel;
import com.xxl.job.core.context.XxlJobHelper;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.jcy.supervise.job.component.converter.BeanConverter;
import com.iflytek.jcy.supervise.job.component.httpinterface.SjztHttpInterface;
import com.iflytek.jcy.supervise.job.component.httpinterface.UapServiceHttpInterface;
import com.iflytek.jcy.supervise.job.component.httpinterface.result.OuterDeptNew;
import com.iflytek.jcy.supervise.job.component.httpinterface.result.OuterDeptPerson;
import com.iflytek.jcy.supervise.job.component.httpinterface.result.OuterResponse;
import com.iflytek.jcy.supervise.job.service.IBatchImportService;
import com.iflytek.sec.uap.dto.ResponseDto;
import com.iflytek.sec.uap.dto.organization.OrgExtendImportDto;
import com.iflytek.sec.uap.dto.user.BatchSaveUserDto;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

/**
 * <br>
 * 标题:UAP组织机构和用户导入服务实现类 <br>
 * 描述: <br>
 * 公司: www.iflytek.com<br>
 *
 * @autho dgyu
 * @time 2022年12月15日 上午11:25:51
 */
@Service
@Slf4j
public class BatchImportServiceImpl implements IBatchImportService {

    @Resource
    private UapServiceHttpInterface uapService;

    @Resource
    private SjztHttpInterface sjztHttpInterface;

    @Resource
    private BeanConverter beanConverter;

    @Value("${sjzt.dwbm}")
    private String sjztDwbm;

    @Resource
    private TokenDto tokenDto;

    @Override
    public void batchImport() throws Exception {
        String param = XxlJobHelper.getJobParam();
        log.info("批量同步组织机构和用户开始,param:{}", param);
        XxlJobHelper.log("批量同步组织机构和用户开始,param:{}", param);
        //获取临时票据
        ResponseDto<UapTokenModel> tokenResp = uapService.getToken(tokenDto);
        if (!tokenResp.isFlag() || tokenResp.getCode() != 0 || ObjectUtils.anyNull(tokenResp) || ObjectUtils.anyNull(tokenResp.getData())) {
            XxlJobHelper.log("获取临时票据失败:{}", tokenResp.getMessage());
            throw new Exception("获取临时票据失败:" + tokenResp.getMessage());
        }
        JSONObject js = new JSONObject();
        js.put("dwbm", sjztDwbm);
        // 中台拿到组织机构数据
        OuterResponse<List<OuterDeptNew>> outerResponse = sjztHttpInterface.depList(js);
        if (null == outerResponse || !outerResponse.getSuccess()) {
            XxlJobHelper.log("从中台拉去单位列表失败:{}", param);
            throw new Exception("从中台拉去单位列表失败:" + param);
        }
        tokenDto.setToken(tokenResp.getData().getToken());
        List<OuterDeptNew> deptList = outerResponse.getData();
        //找到顶级机构 把父机构设置成UAP顶级机构统一认证平台机构：id=0
        List<OrgExtendImportDto> orgExtendImportDtoList = Optional.ofNullable(deptList).map(Collection::stream).map(stream -> stream.map(dept -> beanConverter.fromOuter(dept)).collect(Collectors.toList())).orElse(new ArrayList<>());
        orgExtendImportDtoList.forEach(dept -> {
            dept.setHasChildOrgs(true);
            //找到顶级机构 把父机构设置成UAP顶级机构统一认证平台机构：id=0
            if (sjztDwbm.equals(dept.getUapOrg().getCode())) {
                dept.getUapOrg().setHigherOrg("0");
                dept.getUapOrg().setHigherName("统一认证平台机构");
            }
        });
        this.batchSaveOrg(orgExtendImportDtoList);
        this.batchSaveUser(deptList, param);

    }

    private void batchSaveOrg(List<OrgExtendImportDto> orgExtendImportDtoList) {
        //按照level层级分组 并排序,按照层级 逐层创建,一次性创建机构会报 上级机构不能存在问题
        Map<Integer, List<OrgExtendImportDto>> levelGroupDeptMap = orgExtendImportDtoList.stream().collect(Collectors.groupingBy(v -> v.getUapOrg().getLevel()));
        Map<Integer, List<OrgExtendImportDto>> result = Maps.newLinkedHashMap();
        levelGroupDeptMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(x -> result.put(x.getKey(), x.getValue()));

        result.forEach((k, v) -> {
            //根据code查询上级菜单Id
            Set<String> set = v.stream().filter(org -> !sjztDwbm.equals(org.getUapOrg().getCode())).map(OrgExtendImportDto::getHigherCode).collect(Collectors.toSet());
            String parentOrgCodes = set.stream().collect(Collectors.joining(","));
            if (StringUtils.isNotEmpty(parentOrgCodes)) {
                ResponseDto<List<OrgExtendDto>> parentOrgListResp = uapService.getByCodes(parentOrgCodes, tokenDto.getToken());
                if (null != parentOrgListResp || parentOrgListResp.isFlag()) {
                    List<OrgExtendDto> parentOrg = parentOrgListResp.getData();
                    List<UapOrg> parentUapOrgList = parentOrg.stream().map(OrgExtendDto::getUapOrg).collect(Collectors.toList());
                    //按照code分组 得到父级的机构
                    Map<String, UapOrg> map = parentUapOrgList.stream().collect(Collectors.toMap(xx -> xx.getCode(), xx -> xx));
                    //重新设定上级higherOrgId
                    Iterator<OrgExtendImportDto> it = v.iterator();
                    while (it.hasNext()) {
                        OrgExtendImportDto org = it.next();
                        String higherCode = org.getHigherCode();
                        if (map.containsKey(higherCode)) {
                            org.getUapOrg().setHigherOrg(map.get(higherCode).getId());
                            org.getUapOrg().setHigherName(map.get(higherCode).getName());
                        } else {
                            it.remove();
                        }
                    }
                } else {
                    XxlJobHelper.log("获取上级机构信息失败：level{},message:{}", k, parentOrgListResp.getMessage());
                    log.error("获取上级机构信息失败：level{},message:{}", k, parentOrgListResp.getMessage());
                }
            }
            //对单位编码去重
            List<OrgExtendImportDto> vDistinct = v.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(dept -> dept.getUapOrg().getCode()))), ArrayList::new));
            //排序
            vDistinct.sort(Comparator.comparingLong(xx -> Long.parseLong(xx.getUapOrg().getCode())));
            //设置sort 1-99
            final Integer[] maxSort = new Integer[1];
            maxSort[0] = 1;
            vDistinct.forEach(bb -> {
                if (maxSort[0] < 99) {
                    maxSort[0]++;
                }
                bb.getUapOrg().setSort(maxSort[0]);

            });
            ResponseDto<JSONObject> resp = uapService.batchSaveOrg(vDistinct, tokenDto.getToken());
            XxlJobHelper.log("批量导入组织机构结果vDistinct:{}", JSON.toJSONString(vDistinct));
            log.info("批量导入组织机构结果:resp{}", JSON.toJSONString(resp));
            if (null == resp || !resp.isFlag()) {
                XxlJobHelper.log("层级level组织机构创建失败：level{},message:{}", k, resp.getMessage());
                log.error("层级level组织机构创建失败：level{},message:{}", k, resp.getMessage());
            }
        });
    }

    private void batchSaveUser(List<OuterDeptNew> deptList, String param) {
        if (CollectionUtils.isEmpty(deptList)) {
            return;
        }
        List<String> roleIdList = new ArrayList<>();
        if (StringUtils.isNotEmpty(param)) {
            roleIdList = JSONArray.parseArray(param, String.class);
        }
        Set<String> dwbmSet = deptList.stream().map(OuterDeptNew::getDwbm).collect(Collectors.toSet());
        final List<BatchSaveUserDto> batchSaveUserDtoAll = new ArrayList<>();
        //拉取人员
        dwbmSet.forEach(dwbm -> {
            OuterResponse<List<OuterDeptPerson>> outerPersonResponse = sjztHttpInterface.dwryxx(dwbm);
            if (null != outerPersonResponse && outerPersonResponse.getSuccess()) {
                List<OuterDeptPerson> personList = outerPersonResponse.getData();
                List<BatchSaveUserDto> batchSaveUserDto = Optional.ofNullable(personList).map(Collection::stream).map(stream -> stream.map(person -> beanConverter.fromOuterPerson(person)).collect(Collectors.toList())).orElse(new ArrayList<>());
                batchSaveUserDtoAll.addAll(batchSaveUserDto);
            } else {
                XxlJobHelper.log("从中台拉取人员列表失败dwbm:{},错误信息", dwbm, null == outerPersonResponse ? "" : outerPersonResponse.getMessage());
                log.error("从中台拉取人员列表失败dwbm:{},错误信息", dwbm, null == outerPersonResponse ? "" : outerPersonResponse.getMessage());
            }
        });

        //单位编码集合
        Set<String> set = batchSaveUserDtoAll.stream().map(person -> person.getUser().getOrgCode()).collect(Collectors.toSet());
        String orgCodes = set.stream().collect(Collectors.joining(","));

        ResponseDto<List<OrgExtendDto>> parentOrgListResp = uapService.getByCodes(orgCodes, tokenDto.getToken());
        if (null != parentOrgListResp || parentOrgListResp.isFlag()) {
            List<OrgExtendDto> parentOrg = parentOrgListResp.getData();
            List<UapOrg> parentUapOrgList = parentOrg.stream().map(OrgExtendDto::getUapOrg).collect(Collectors.toList());
            //按照code分组 得到父级的机构
            Map<String, UapOrg> map = parentUapOrgList.stream().collect(Collectors.toMap(xx -> xx.getCode(), xx -> xx));
            //重新设定上级orgId
            Iterator<BatchSaveUserDto> it = batchSaveUserDtoAll.iterator();
            while (it.hasNext()) {
                BatchSaveUserDto user = it.next();
                String higherCode = user.getUser().getOrgCode();
                if (map.containsKey(higherCode)) {
                    user.getUapOrg().setId(map.get(higherCode).getId());
                    user.getUapOrg().setHigherOrg(map.get(higherCode).getId());
                    user.getUapOrg().setHigherName(map.get(higherCode).getName());
                    user.getUser().setOrgId(map.get(higherCode).getId());
                    user.getUser().setOrgName(map.get(higherCode).getName());
                    //设置使用Uap中配置的默认密码123456
                    user.getUser().setIsDefaultPwd(true);
                } else {
                    it.remove();
                }
            }
        } else {
            XxlJobHelper.log("获取上级机构信息失败：message:{}", parentOrgListResp.getMessage());
            log.error("获取上级机构信息失败：message:{}", parentOrgListResp.getMessage());
        }
        //mock数据有rybm重复 ：批量导入用户失败:批量导入的用户名重复,请检查5329230006数据是否正确
        List<BatchSaveUserDto> batchSaveUserDtoAllFinal = batchSaveUserDtoAll.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<BatchSaveUserDto>(Comparator.comparing(user -> user.getUser().getLoginName()))), ArrayList::new));
        XxlJobHelper.log("批量导入用户共计:{}", batchSaveUserDtoAllFinal.size());
        XxlJobHelper.log("导入用户数据是:{}", JSON.toJSONString(batchSaveUserDtoAllFinal, SerializerFeature.DisableCircularReferenceDetect));
        log.error("批量导入用户共计:{}", batchSaveUserDtoAllFinal.size());
        ResponseDto<JSONObject> saveUserResponse = this.uapService.batchRegister(batchSaveUserDtoAllFinal, tokenDto.getToken());
        XxlJobHelper.log("批量导入用户结果:resp{}", JSON.toJSONString(saveUserResponse));
        log.info("批量导入用户结果:resp{}", JSON.toJSONString(saveUserResponse));
        if (null == saveUserResponse || !saveUserResponse.isFlag()) {
            XxlJobHelper.log("批量导入用户失败:{}", saveUserResponse.getMessage());
            log.error("批量导入用户失败:{}", saveUserResponse.getMessage());
        }
        //给用户绑定角色
        List<String> finalRoleIdList = roleIdList;
        batchSaveUserDtoAllFinal.forEach(user -> {
            // 根据登录名查询用户信息
            ResponseDto<BatchSaveUserDto> responseUserDetail = this.uapService.getUserDetailByLoginName(user.getUser().getLoginName(), this.tokenDto.getToken());
            if (!responseUserDetail.isFlag() || responseUserDetail.getCode() != 0 || ObjectUtils.anyNull(responseUserDetail) || ObjectUtils.anyNull(responseUserDetail.getData())) {
                XxlJobHelper.log("查询用户失败loginName{}", responseUserDetail.getMessage());
                log.error("批量导入用户失败loginName{}", responseUserDetail.getMessage());
            } else {
                BindRoleListToUserDto bindRoleListToUserDto = new BindRoleListToUserDto();
                bindRoleListToUserDto.setUserId(responseUserDetail.getData().getUser().getLoginName());
                bindRoleListToUserDto.setRoleIdList(finalRoleIdList);
                this.uapService.bindRole(bindRoleListToUserDto, tokenDto.getToken());
            }
        });
    }
}
